package cn.tedu.charging.order.service.impl;

import cn.tedu.charging.common.constant.AmqpComponentConst;
import cn.tedu.charging.common.constant.MqttDestinationConst;
import cn.tedu.charging.common.pojo.message.ChargingStartCheckMessage;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.common.pojo.param.OrderAddParam;
import cn.tedu.charging.common.protocol.JsonResult;
import cn.tedu.charging.common.utils.CronUtil;
import cn.tedu.charging.common.utils.SnowflakeIdGenerator;
import cn.tedu.charging.common.utils.XxlJobTaskUtil;
import cn.tedu.charging.order.amqp.AmqpProducerClient;
import cn.tedu.charging.order.client.DeviceClient;
import cn.tedu.charging.order.client.UserClient;
import cn.tedu.charging.order.mqtt.MqttProducerClient;
import cn.tedu.charging.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private DeviceClient deviceClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private MqttProducerClient mqttProducerClient;
    @Autowired
    private AmqpProducerClient amqpProducerClient;
    //构造方法 入参
    //datacenterId 数据中心的id值 支持0~31数字
    //machineId 机器id 0~31
    SnowflakeIdGenerator generator=new SnowflakeIdGenerator(1,1);
    @Override
    public String createOrder(OrderAddParam param) {
        log.debug("扫码下单请求处理业务,入参:{}",param);
        //1.调用设备 检查当前用户正在扫码的这把枪是否可用
        checkGunAvailable(param.getGunId());
        //2.调用车主 检查是否可给该车主充电
        checkUserChargeAllowed(param.getUserId(),param.getGunId());
        //3.生成高并发的编码 雪花算法
        String billId=generator.nextId()+"";
        //4.给设备命令 开始自检
        sendStartCheck(param,billId);
        //5.发送延迟消息,检查自检响应结果
        sendDelayCheck(param,billId);
        //6.生成一个定时任务 为该订单做兜底检查 TODO
        /*XxlJobTaskUtil.createJobTask(
                CronUtil.delayCron(1000*60*2),
                "order-executor",
                billId);*/
        //7.枪被占用 修改枪状态(轻做) TODO
        log.debug("扫码下单请求处理业务,入参:{},出参:{}",param,billId);
        return billId;
    }

    private void sendDelayCheck(OrderAddParam param, String billId) {
        //1.组织一个对象
        DelayCheckMessage message=new DelayCheckMessage();
        message.setOrderNo(billId);
        message.setUserId(param.getUserId());
        message.setPileId(param.getPileId());
        message.setGunId(param.getGunId());
        message.setVehicleId(1);
        //2.定义延迟时间 5秒 10秒 20秒 30秒 最长的自检时间 还要多一段时间 1分钟
        long ttl=1000*60;
        amqpProducerClient.sendDelay(AmqpComponentConst.DELAY_BILL_EX,message,ttl);
    }

    private void sendStartCheck(OrderAddParam param, String billId) {
        //发消息 charging/device/check/+pileId
        String target= MqttDestinationConst.START_GUN_CHECK_PREFIX+param.getPileId();
        //ChargingStartCheckMessage
        ChargingStartCheckMessage message=new ChargingStartCheckMessage();
        message.setOrderNo(billId);
        message.setGunId(param.getGunId());
        message.setUserId(param.getUserId());
        mqttProducerClient.send(target,message);
    }

    private void checkUserChargeAllowed(Integer userId, Integer gunId) {
        JsonResult<Boolean> result = userClient.checkChargeOk(userId, gunId);
        //拿到包装 布尔
        Boolean allowed = result.getData();
        if (!allowed){
            log.error("该用户:{},不允许在该枪:{}充电",userId,gunId);
            throw new RuntimeException("不许充电");
        }
    }

    private void checkGunAvailable(Integer gunId) {
        JsonResult<Boolean> result = deviceClient.checkGunAvailable(gunId);
        //拿到结果的 布尔
        Boolean available = result.getData();
        if (!available) {
            log.error("当前枪状态不可用");
            throw new RuntimeException("不可用");
        }
    }
}
